# 使用蓝图对象
from flask import request

from . import news_blu
from flask import session, render_template, current_app, jsonify,g
# 导入模型类
from info.models import User,News,Category
# 导入自定义的状态码
from info.utils.response_code import RET
from  info import  constants
# 导入装饰器包
from info.utils.common  import  login_required


# 2----使用蓝图对象
@news_blu.route('/')
def index():
    """
    展示用户的登录信息(用户的登录状态)：
    1、尝试从redis中获取user_id
    2、根据user_id查询数据库
    3、判断查询结果
    4、返回用户的基本信息给模板
    5、通过模板来渲染用户信息
    :return:
    """
    # 因为注册和登录时已经在redis中缓存了用户信息
    user_id = session.get('user_id')
    # 定义变量默认为None，用来保存查询结果
    user = None
    # 如果用户已经登录
    if user_id:
        # 根据user_id来查询mysql数据库
        try:
            user = User.query.filter_by(id=user_id).first()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR,errmsg='查询数据失败')
        # 判断查询结果
        if not user:
            return jsonify(errno=RET.NODATA,errmsg='没有用户数据')
    # 展示的新闻列表点击排行
    try:
        # 默认实现是按照新闻点击次数进行的查询，并写分页6条数据
        # 导入medoles里面的News数据库 里面有点击数据列
        news_list=News.query.order_by(News.clicks.desc()).limit(6)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询新闻数据失败")
    #判断查询结果是否有数据
    if not news_list:
        return jsonify(errno=RET.NODATA,errmsg="无新闻排行数据")
    #如果有数据，定义容器来存储新闻数据
    click_news_list=[]
    #遍历查询到的结果
    for news in news_list if news_list else []:
        # 模型类中定义的方法，获取对象的数据，类似于__repr__方法的作用
        click_news_list.append(news.to_basic_dict())
    #展示项目首页分类数据
    try:
        # 先获取所有的分类数据
        categories=Category.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询分类数据失败")
    if not categories:
        return jsonify(errno=RET.NODATA,errmsg="没有查询到分类数据")
    #定义容器，用来保存遍历到的所有分类数据
    category_list=[]
    for category in categories:
        category_list.append(category.to_dict())

        # 定义字典，用来保存用户的基本信息，包括头像、昵称、手机号等
        # if user:
        #     return 字典
        # else:
        #     return None
    # 如果用户已登录，调用模型类中to_dict方法，可以把查询的对象转成可读字符串，类似于__repr__方法
    data = {
            "user_info":user.to_dict() if user else None,
            "click_news_list":click_news_list,
            "category_list":category_list
    }

    return render_template('news/index.html',data=data)
@news_blu.route("/news_list")
@login_required
def news_list():
    """
        首页新闻列表数据加载
        1、获取参数，args，cid新闻分类id、page页数、per_page每页数据条目
        var params ={
            'cid'：分类id
            ‘page’:page,
            'per_page':per_page
        }
        $.get(/news_list,parmams,function(resp))
        2、校验参数,把参数转成整型值
        3、查询数据库，根据分类id进行过滤查询，默认按照新闻发布时间进行排序，
        对排序结果进行分页paginate(page,每页条目数，False)
        4、分页查询返回的是分页对象
        paginate.items
        paginate.pages
        paginate.page
        5、遍历分页后的数据，调用模型类中的方法，获取分页后的新闻数据
        6、返回结果
        :return:
        """
#     获取get请求的查询字符串，新闻分类id,默认第一个分类
    cid=request.args.get("cid",1)
    # 默认显示第一页
    page=request.args.get("page",1)
    # 默认每页10条数据
    per_page=request.args.get("per_page",10)
#     检查参数 把参数转成int类型
    try:
        cid,page,per_page=int(cid),int(page),int(per_page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR,errmsg="数据参数错误")
#     根据分类id进行查询
# 定义变量 存储过滤条件
    filters=[]
    # 当分类id大于1的时候 获取另外分类的数据
    if cid > 1:
        # 往列表里面添加另外一个分类的数据
        filters.append(News.category_id==cid)
    try:
# 默认按照分类id进行过滤，其次按照新闻发布时间进行排序，paginate分页参数1为页数，
# 参数2每页的新闻数目，参数3分页异常不报错  *filters是上面那一类
        paginate=News.query.filter(*filters).order_by(News.create_time.desc()).paginate\
            (page,constants.HOME_PAGE_MAX_NEWS,False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(RET.DBERR,errmsg="查询列表新闻数据失败")
#     获取分页后的新闻数据模型对象/总页数/当前页数
    news_list=paginate.items
    total_page=paginate.pages
    current_pape=paginate.page
#     遍历分页后的对象
    news_dict_list=[]
    # news_list就是这个分类里面的新闻对象
    for news in news_list:
        news_dict_list.append(news.to_dict())
#         返回数据
    data = {
        "news_dict_list":news_dict_list,
        "total_page":total_page,
        "cirrent_page":current_pape
    }
    return jsonify(errno=RET.OK,errmsg="OK",data=data)
@news_blu.route("/<int:news_id>")
@login_required
def get_news_detail(news_id):
    """
    新闻详情页面
    1.获取信息id
    2.根据新闻id来查询数据库
    3.校验查询结果
    4.返回新闻的数据，to_dict（）
    :param news_id:
    :return:
    """
#     根据新闻id查询数据库
    try:
        news=News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='查询新闻详情数据失败')
#     校验查询结果
    if not news:
        return jsonify(errno=RET.NODATA,errmsg='无新闻数据')
#     展示项目首页分类数据
    try:
        categories = Category.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询分类数据失败")
#     判断查询结果
    if not categories:
        return jsonify(errno=RET.NODATA,errmsg="无分类数据 ")
    # 再次查询分类 是为了在看详情页面的加载 也显示点击排行
    category_list=[]
    for category in categories:
        category_list.append(category.to_dict())
    data={
        "news" : news.to_dict(),
        "catefory_list" : category_list
    }
    # 调用模板页面返回数据
    return render_template("news/detail.html",data=data)

@news_blu.route('/news_collect',methods=['POST'])
@login_required
def news_collect():
    """
    收藏或取消收藏
    1、尝试获取用户信息
    2、获取参数news_id,action
    3、检查news_id必须为整型值
    4、检查action参数必须为collect/cancel_collect;;;;'collect', 'cancel_collect'
    5、查询新闻数据，确认新闻的存在
    6、校验查询结果
    7、判断用户选择的是收藏还是取消收藏
    收藏：user.collection_news.append(news)
    取消：user.collection.remove(news)
    8、返回结果

    :return:
    """
#     获取用户信息
    user=g.user
#     判断用户是否登录
    if not user:
        return jsonify(errno=RET.SESSIONERR,errmsg="用户没有登录")
#     获取参数
    news_id=request.json.get("news_id")
    action=request.json.get("action")
#     对news_id进行强转成int
    try:
        news_id = int(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return  jsonify(errno=RET.PARAMERR,errmsg='参数格式错误')
#     对action行为进行检查
    if action not in["collect","cancel_collect"]:
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')
#     根据news_id查询数据库
    try:
        news=News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据失败')
#     判断用户选择是收藏还是取消收藏
    if action=="collect":
#         判断用户是否收藏过  collection_news当前用户收藏的所有新闻都在这里面
        if news not in user.collection_news:
            user.collection_news.append(news)
        else:
            user.collection_news.remove(news)

    return jsonify(errno=RET.OK, errmsg='OK')



@news_blu.route('/favicon.ico')
def favicon_image():
    # 使用应用上下文调用Flask内置的发送静态文件的方法，发送一个文件，给浏览器
    return current_app.send_static_file('news/favicon.ico')

